/** @file
Platform Acpi table Update Driver.

Copyright (C) 2023, Phytium Technology Co Ltd. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <PiDxe.h>

#include <IndustryStandard/Acpi.h>
#include <IndustryStandard/AcpiAml.h>

#include <Library/AcpiHelperLib.h>
#include <Library/AmlLib/AmlLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/ParameterTable.h>
#include <Library/PcdLib.h>
#include <Library/PssiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>

#include <Protocol/AcpiTable.h>
#include <Protocol/AcpiSystemDescriptionTable.h>
#include <Protocol/FirmwareVolume2.h>

#define EFI_ACPI_MAX_NUM_TABLES         20
#define MAX_PCI_HOST_COUNT              8
#define AML_PATH_SIZE                   10

/**
  Update Ssdt table,the default Ssdt table describes 8 Pcie Host node,
  delete nodes based on actual situation.
**/
VOID
SsdtUpdate (
  VOID
  )
{
  EFI_STATUS                    Status;
  UINTN                         TableKey;
  UINT8                         Index;
  UINT8                         PciHostIndex;
  EFI_ACPI_SDT_HEADER           *Table;
  EFI_ACPI_SDT_PROTOCOL         *AcpiTableProtocol;
  EFI_ACPI_TABLE_PROTOCOL       *AcpiTable;
  EFI_ACPI_TABLE_VERSION        TableVersion;
  EFI_ACPI_DESCRIPTION_HEADER   **NewTable;
  AML_ROOT_NODE_HANDLE          RootNodeHandle;
  AML_OBJECT_NODE_HANDLE        NameOpIdNode;
  UINTN                         TableSize;
  UINTN                         TableHandle;
  EFI_HOB_GUID_TYPE             *GuidHob;
  PHYTIUM_PCI_HOST_BRIDGE       *PciHostBridge;
  UINT8                         PciHostCount;
  CHAR8                         AslPath[AML_PATH_SIZE + 1];

  GuidHob = GetFirstGuidHob(&gPlatformPciHostInforGuid);
  if (GuidHob == NULL) {
    Status = EFI_NOT_FOUND;
    DEBUG ((DEBUG_ERROR,"Not Find PciHostInfo\n"));
    ASSERT_EFI_ERROR(Status);
  }

  PciHostBridge = (PHYTIUM_PCI_HOST_BRIDGE *) GET_GUID_HOB_DATA(GuidHob);
  PciHostCount = (UINT8)PciHostBridge->PciHostCount;

  NewTable = (EFI_ACPI_DESCRIPTION_HEADER**)
              AllocateZeroPool (
                (sizeof (EFI_ACPI_DESCRIPTION_HEADER*))
              );

  if (NewTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    DEBUG ((
      DEBUG_ERROR,
      "ERROR: DSDT-FIXUP: Failed to allocate memory for Table ."
      " Status = %r\n",
      Status
      ));
    ASSERT_EFI_ERROR(Status);
  }

  // Find the AcpiTable protocol
  Status = gBS->LocateProtocol(&gEfiAcpiSdtProtocolGuid, NULL, (VOID**) &AcpiTableProtocol);
  if (EFI_ERROR(Status)) {
    DEBUG((DEBUG_ERROR, "Unable to locate ACPI Sdt protocol\n"));
    ASSERT_EFI_ERROR(Status);
  }

  // Search for SSDT Table
  for (Index = 0; Index < EFI_ACPI_MAX_NUM_TABLES; Index++) {
    Status = AcpiTableProtocol->GetAcpiTable(Index, &Table, &TableVersion, &TableKey);
    if (EFI_ERROR(Status))
      break;
    if (Table->Signature != EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)
      continue;

    Status = AmlParseDefinitionBlock (
             (CONST EFI_ACPI_DESCRIPTION_HEADER *)Table,
             &RootNodeHandle
             );

    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: SSDT-FIXUP:"
        " Failed to parse SSDT Template. Status = %r\n",
        Status
        ));
      ASSERT_EFI_ERROR(Status);
    }

    CopyMem (AslPath, "\\_SB_.PCIx", AML_PATH_SIZE + 1);
    for (PciHostIndex = PciHostCount; PciHostIndex < MAX_PCI_HOST_COUNT; PciHostIndex++) {
      AslPath[AML_PATH_SIZE - 1] = AsciiFromHex (PciHostIndex);
      DEBUG ((DEBUG_INFO, "AslPath:%a\n", AslPath));

      Status = AmlFindNode (
                 RootNodeHandle,
                 AslPath,
                 &NameOpIdNode
                 );
      if (EFI_SUCCESS == Status) {
        AmlDetachNode(NameOpIdNode);
        DEBUG((DEBUG_INFO, "Delete %a\n", AslPath));
      }
    }

    // Serialize the tree.
    Status = AmlSerializeDefinitionBlock (
               RootNodeHandle,
               NewTable
               );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: SSDT-FIXUP: Failed to Serialize SSDT Table Data."
        " Status = %r\n",
        Status
        ));
      ASSERT_EFI_ERROR(Status);
    }

    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable);
    if (EFI_ERROR (Status)) {
      DEBUG((DEBUG_ERROR, "Unable to locate ACPI Sdt protocol\n"));
      ASSERT_EFI_ERROR(Status);
    }

    Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
    if (EFI_ERROR(Status)) {
      DEBUG((DEBUG_ERROR, "ERROR: DSDT-FIXUP: Failed to uninstall Dsdt table.\n"));
      ASSERT_EFI_ERROR(Status);
    }

    TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) *NewTable)->Length;
    //
    // Install ACPI table
    //
    Status = AcpiTable->InstallAcpiTable (
                          AcpiTable,
                          *NewTable,
                          TableSize,
                          &TableHandle
                          );

    if (EFI_ERROR(Status)) {
      DEBUG((DEBUG_ERROR, "ERROR: DSDT-FIXUP: Failed to install Dsdt table.\n"));
      ASSERT_EFI_ERROR(Status);
    }

    if (RootNodeHandle != NULL) {
      Status = AmlDeleteTree (RootNodeHandle);
      if (EFI_ERROR (Status)) {
        DEBUG ((
          DEBUG_ERROR,
          "ERROR: SSDT-FIXUP: Failed to cleanup AML tree."
          " Status = %r\n",
          Status
          ));
        ASSERT_EFI_ERROR(Status);
      }
    }
  }
}

/**
  Update ThermalZone node(TZXX) according to die number.
  The ThermalZone.asl in the DSDT table describes a total of 16 ThermalZone
  nodes when all 8 die are enabled. The function removes the ThermalZone nodes
  corresponding to the actually disabled die.

  @param[in]  RootHandle      Pointer to the root of an AML tree.

  @retval  EFI_SUCCESS            The function completed successfully.
**/
STATIC
EFI_STATUS
UpdateThermalZoneNode (
  AML_ROOT_NODE_HANDLE  RootHandle
  )
{
  EFI_STATUS                Status;
  AML_OBJECT_NODE_HANDLE    NameOpIdNode;
  UINT8                     Num;

  Num = 0;
  //
  //Get die number from parameter table.
  //
  Status = GetDieNumFromParTable (&Num);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Get Die Number Failed!\n"));
    return EFI_NOT_FOUND;
  }
  DEBUG ((DEBUG_INFO, "Die Number : %d\n", Num));
  //
  //Removes ThermalZone nodes
  //
  //Removes Die7 ThermalZone nodes
  if (Num < 8) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ70", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ70 Node\n"));
    }
  }

  //Removes Die6 ThermalZone nodes
  if (Num < 7) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ60", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ60 Node\n"));
    }
  }
  //Removes Die5 ThermalZone nodes
  if (Num < 6) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ50", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ50 Node\n"));
    }
  }
  //Removes Die4 ThermalZone nodes
  if (Num < 5) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ40", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ40 Node\n"));
    }
  }
  //Removes Die3 ThermalZone nodes
  if (Num < 4) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ30", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ30 Node\n"));
    }
  }
  //Removes Die2 ThermalZone nodes
  if (Num < 3) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ20", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ20 Node\n"));
    }
  }
  //Removes Die1 ThermalZone nodes
  if (Num < 2) {
    Status = AmlFindNode (RootHandle, "\\_SB.TZ10", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.TZ10 Node\n"));
    }
  }
  //There is no situation where the die number is 0.

  return EFI_SUCCESS;
}

/**
  Update PMU node according to die number.

  @param[in]  RootHandle      Pointer to the root of an AML tree.

  @retval  EFI_SUCCESS            The function completed successfully.
**/
STATIC
EFI_STATUS
UpdatePmuNode (
  AML_ROOT_NODE_HANDLE  RootHandle
  )
{

  EFI_STATUS                Status;
  AML_OBJECT_NODE_HANDLE    NameOpIdNode;
  UINT8                     Num;

  Num = 0;
  //
  //Get die number from parameter table.
  //
  Status = GetDieNumFromParTable (&Num);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Get Die Number Failed!\n"));
    return EFI_NOT_FOUND;
  }
  DEBUG ((DEBUG_INFO, "Die Number : %d\n", Num));
  //
  //Removes PMU nodes
  //
  //Removes Die7 PMU nodes
  if (Num < 8) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC70", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC70 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC71", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC71 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC72", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC72 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC73", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC73 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC70", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC70 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC71", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC71 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC72", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC72 Node\n"));
    }
  }
  //Removes Die6 PMU nodes
  if (Num < 7) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC60", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC60 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC61", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC61 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC62", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC62 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC63", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC63 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC60", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC60 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC61", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC61 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC62", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC62 Node\n"));
    }
  }
  //Removes Die5 PMU nodes
  if (Num < 6) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC50", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC50 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC51", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC51 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC52", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC52 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC53", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC53 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC50", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC50 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC51", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC51 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC52", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC52 Node\n"));
    }
  }
  //Removes Die4 PMU nodes
  if (Num < 5) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC40", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC40 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC41", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC41 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC42", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC42 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC43", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC43 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC40", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC40 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC41", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC41 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC42", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC42 Node\n"));
    }
  }
  //Removes Die3 PMU nodes
  if (Num < 4) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC30", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC30 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC31", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC31 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC32", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC32 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC33", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC33 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC30", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC30 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC31", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC31 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC32", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC32 Node\n"));
    }
  }
  //Removes Die2 PMU nodes
  if (Num < 3) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC20", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC20 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC21", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC21 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC22", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC22 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC23", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC23 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC20", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC20 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC21", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC21 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC22", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC22 Node\n"));
    }
  }
  //Removes Die1 PMU nodes
  if (Num < 2) {
    //DDR
    Status = AmlFindNode (RootHandle, "\\_SB.MC10", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC10 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC11", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC11 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC12", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC12 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.MC13", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.MC13 Node\n"));
    }
    //PEU
    Status = AmlFindNode (RootHandle, "\\_SB.PC10", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC10 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC11", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC11 Node\n"));
    }
    Status = AmlFindNode (RootHandle, "\\_SB.PC12", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.PC12 Node\n"));
    }
  }
  //There is no situation where the die number is 0.

  return EFI_SUCCESS;
}


/**
  Update CEU nodeCEUX) according to die number.

  @param[in]  RootHandle      Pointer to the root of an AML tree.

  @retval  EFI_SUCCESS            The function completed successfully.
**/
STATIC
EFI_STATUS
UpdateCeuNode (
  AML_ROOT_NODE_HANDLE  RootHandle
  )
{
  EFI_STATUS                Status;
  AML_OBJECT_NODE_HANDLE    NameOpIdNode;
  UINT8                     Num;

  Num = 0;
  //
  //Get die number from parameter table.
  //
  Status = GetDieNumFromParTable (&Num);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "Get Die Number Failed!\n"));
    return EFI_NOT_FOUND;
  }
  DEBUG ((DEBUG_INFO, "Die Number : %d\n", Num));
  //
  //Removes CEU nodes
  //
  //Removes Die7 CEU nodes
  if (Num < 8) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU7", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU7 Node\n"));
    }
  }

  //Removes Die6 CEU nodes
  if (Num < 7) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU6", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU6 Node\n"));
    }
  }
  //Removes Die5 CEU nodes
  if (Num < 6) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU5", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU5 Node\n"));
    }
  }
  //Removes Die4 CEU nodes
  if (Num < 5) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU4", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU4 Node\n"));
    }
  }
  //Removes Die3 CEU nodes
  if (Num < 4) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU3", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU3 Node\n"));
    }
  }
  //Removes Die2 CEU nodes
  if (Num < 3) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU2", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU2 Node\n"));
    }
  }
  //Removes Die1 CEU nodes
  if (Num < 2) {
    Status = AmlFindNode (RootHandle, "\\_SB.CEU1", &NameOpIdNode);
    if (EFI_SUCCESS == Status) {
      AmlDetachNode (NameOpIdNode);
      DEBUG ((DEBUG_INFO, "Delete Open _SB.CEU1 Node\n"));
    }
  }
  //There is no situation where the die number is 0.

  return EFI_SUCCESS;

}

/**
  Update DSDT Table.
**/
VOID
DsdtUpdate (
  VOID
  )
{
  EFI_STATUS                   Status;
  EFI_STATUS                   Status1;
  UINTN                        TableKey;
  UINTN                        Index;
  EFI_ACPI_SDT_HEADER          *Table;
  EFI_ACPI_SDT_PROTOCOL        *AcpiTableProtocol;
  EFI_ACPI_TABLE_PROTOCOL      *AcpiTable;
  EFI_ACPI_TABLE_VERSION       TableVersion;
  EFI_ACPI_DESCRIPTION_HEADER  **NewTable;
  AML_ROOT_NODE_HANDLE         RootNodeHandle;
  UINTN                        TableSize;
  UINTN                        TableHandle;

  NewTable = (EFI_ACPI_DESCRIPTION_HEADER**) AllocateZeroPool ((sizeof (EFI_ACPI_DESCRIPTION_HEADER*)));

  if (NewTable == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    DEBUG ((
      DEBUG_ERROR,
      "ERROR: DSDT-FIXUP: Failed to allocate memory for Table ."
      " Status = %r\n",
      Status
      ));
    ASSERT_EFI_ERROR (Status);
  }

  //
  // Find the AcpiTable protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiAcpiSdtProtocolGuid,
                  NULL,
                  (VOID**) &AcpiTableProtocol
                  );
  if (EFI_ERROR(Status)) {
    DEBUG((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
    ASSERT_EFI_ERROR (Status);
  }

  //
  // Search for DSDT Table
  //
  for (Index = 0; Index < EFI_ACPI_MAX_NUM_TABLES; Index++) {
    Status = AcpiTableProtocol->GetAcpiTable(Index, &Table, &TableVersion, &TableKey);
    if (EFI_ERROR(Status)) {
      break;
    }
    if (Table->Signature != EFI_ACPI_6_4_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
      continue;
    }

    Status = AmlParseDefinitionBlock (
             (CONST EFI_ACPI_DESCRIPTION_HEADER *)Table,
             &RootNodeHandle
             );

    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: DSDT-FIXUP:"
        " Failed to parse DSDT Template. Status = %r\n",
        Status
        ));
      ASSERT_EFI_ERROR (Status);
    }
    //
    //Update all dsdt node
    //
    UpdateThermalZoneNode (RootNodeHandle);
    UpdateCeuNode (RootNodeHandle);
    UpdatePmuNode (RootNodeHandle);
    //
    // Serialize the tree.
    //
    Status = AmlSerializeDefinitionBlock (
               RootNodeHandle,
               NewTable
               );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "ERROR: DSDT-FIXUP: Failed to Serialize DSDT Table Data."
        " Status = %r\n",
        Status
        ));
      ASSERT_EFI_ERROR(Status);
    }

    Status = gBS->LocateProtocol (
                    &gEfiAcpiTableProtocolGuid,
                    NULL,
                    (VOID**)&AcpiTable
                    );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR(Status);
    }

    Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
    if (EFI_ERROR(Status)) {
      DEBUG ((DEBUG_ERROR, "ERROR: DSDT-FIXUP: Failed to uninstall Dsdt table.\n"));
      ASSERT_EFI_ERROR(Status);
    }

    TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) *NewTable)->Length;
    //
    // Install ACPI table
    //
    Status = AcpiTable->InstallAcpiTable (
                          AcpiTable,
                          *NewTable,
                          TableSize,
                          &TableHandle
                          );

    if (EFI_ERROR(Status)) {
      DEBUG((DEBUG_ERROR, "ERROR: DSDT-FIXUP: Failed to install Dsdt table.\n"));
      ASSERT_EFI_ERROR(Status);
    }

    if (RootNodeHandle != NULL) {
      Status1 = AmlDeleteTree (RootNodeHandle);
      if (EFI_ERROR (Status1)) {
        DEBUG ((
          DEBUG_ERROR,
          "ERROR: DSDT-FIXUP: Failed to cleanup AML tree."
          " Status = %r\n",
          Status1
          ));
      ASSERT_EFI_ERROR(Status1);
      }
    }
  }
}

/**
  This function is the entrypoint of the AcpiUpdate driver.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.

  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
**/
EFI_STATUS
EFIAPI
AcpiUpdateDxeEntry (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{

  DEBUG ((DEBUG_INFO, "Acpi Update\n"));
  SsdtUpdate ();
  DsdtUpdate ();

  return EFI_SUCCESS;
}

